#ifndef COMMON_REFLECT_REFLECT_CLASS_H_
#define COMMON_REFLECT_REFLECT_CLASS_H_
#pragma once

#include <string>
#include <iostream>
#include <typeinfo>
#include <memory>
#include <unordered_map>
#include <cxxabi.h>
#include <functional>

namespace common {

template<typename B, typename... Args>
class ClassFactory {
 typedef std::function<B* (Args && ...)> Creator;
 typedef std::shared_ptr<std::unordered_map<std::string, Creator>> CreatorMap;
 typedef std::shared_ptr<std::unordered_map<std::string, B*>> ObjectMap;

 public:
  static ClassFactory* Instance() {
    if (!factory_) {
      factory_ = new ClassFactory();
    }
    return factory_;
  }

  bool Regist(const std::string& str_type_name, Creator creator) {
    if (!creator) {
      std::cout << "creator == nullptr" << std::endl;
      return false;
    }
    return creator_map_->insert({str_type_name, creator}).second;
  }

  B* Create(const std::string& str_type_name, Args... args) {
    auto iter = creator_map_->find(str_type_name);
    if (iter == creator_map_->end()) {
      return nullptr;
    }
    return iter->second(std::forward<Args>(args)...);
  }

 private:
  ClassFactory() {
    creator_map_ = std::make_unique<std::unordered_map<std::string, Creator>>();
  }
  static ClassFactory<B, Args...>* factory_;
  CreatorMap creator_map_;
};

template<typename B, typename ... Args>
ClassFactory<B, Args...>* ClassFactory<B, Args...>::factory_ = nullptr;

template<typename B, typename T, typename ...Args>
class DynamicCreator {
 public:
  struct Register {
    Register(){
      std::cout << "reg " << abi::__cxa_demangle(
          typeid(T).name(), nullptr, nullptr, nullptr) << std::endl;
      char* sz_demangle_name = nullptr;
      std::string str_type_name;
      sz_demangle_name = abi::__cxa_demangle(
          typeid(T).name(), nullptr, nullptr, nullptr);
      if (sz_demangle_name) {
        str_type_name = sz_demangle_name;
        free(sz_demangle_name);
      }
      ClassFactory<B, Args...>::Instance()->Regist(str_type_name, CreateObject);
    }
    void DoNothing(){}
  };

  DynamicCreator() {
    register_.DoNothing();
  }
  virtual ~DynamicCreator(){
    register_.DoNothing();
  }

  static B* CreateObject(Args &&... args) {
    return new T(std::forward<Args>(args)...);
  }
  static Register register_;
};

template<typename B, typename T, typename ...Args>
typename DynamicCreator<B, T, Args...>::Register
  DynamicCreator<B, T, Args...>::register_;

}


#endif  // COMMON_REFLECT_CLASS_H_
